home *** CD-ROM | disk | FTP | other *** search
- /* Functions for displaying, changing, reading, and saving application
- preferences.
-
- 94/01/12 aih - overrides popup controls' mouse down handler
- 93/12/23 aih - created */
-
- #include <Packages.h>
- #include <Script.h>
- #include "pstr.h"
- #include "ApplicationPreferencesLib.h"
- #include "ArchiveLib.h"
- #include "DialogLib.h"
- #include "FontLib.h"
- #include "MemoryLib.h"
- #include "MenuLib.h"
- #include "PopupLib.h"
- #include "PreferencesLib.h"
- #include "ResourceConstantsLib.h"
- #include "ResourceLib.h"
- #include "ResourceTypeLib.h"
- #include "TextWrapDialogLib.h"
-
- /* version of preferences data */
- #define APP_PREFS_VERSION (1)
-
- /* items in preferences dialog */
- enum {
-
- iTextFrame = 1,
- iTextTitle,
-
- iStyleFrame,
- iStyleTitle,
- iStyledButton,
- iUnstyledButton,
- iExtendedButton,
-
- iWrapFrame,
- iWrapTitle,
- iWrapButton,
- iWrapDontButton,
- iWrapMarginText,
- iWrapUnitsText,
-
- iFontPopup,
- iSizeTitle,
- iSizeText,
- iSizePopup,
- iJustPopup,
-
- iUnitsPopup,
-
- iDefaultsButton,
-
- /* items that are used to identify objects */
- iWrapRadioGroup = iWrapFrame,
- iStyleRadioGroup = iStyleFrame,
-
- iLast
- };
-
- /* conversion factors from units to pixels */
- #define MAX_UNITS (RLS_UNITS_LAST - 1)
- #define CENT_PER_INCH (2.54)
- #define PIXELS_PER_INCH (72.0) /* IM-VI, p12-7 */
- #define POINTS_PER_INCH (72.27) /* IM-VI, p12-7 */
- static float gUnitConversions[MAX_UNITS] = {
- PIXELS_PER_INCH / CENT_PER_INCH / 10, /* pixels per millimeter */
- PIXELS_PER_INCH / CENT_PER_INCH, /* pixels per centimeter */
- PIXELS_PER_INCH, /* pixels per inch */
- PIXELS_PER_INCH / POINTS_PER_INCH, /* pixels per point */
- };
-
- static AppPrefsWindowHandle gAppPrefsWindow;
-
- /* return a handle to the popup control's menu */
- static MenuHandle CtlPopupMenu(ControlHandle ctl)
- {
- require(CtlValid(ctl));
- return((**(PopupPrivateHandle) (**ctl).contrlData).mHandle);
- }
-
- /* return the menu of a popup control in the dialog */
- static MenuHandle DlgPopupMenu(DialogPtr dlg, short item)
- {
- return(CtlPopupMenu(DlgCtl(dlg, item)));
- }
-
- /* return default values for preferences */
- const AppPrefsType *AppPrefsDefaults(void)
- {
- static AppPrefsType defaults;
- static Boolean initialized;
-
- if (! initialized) {
- /* word wrap is enabled if text is right justified since TextEdit
- doesn't display the text correctly if it's right justified and
- word wrap is disabled */
- defaults.text.kind = TX_STYLED_KIND;
- defaults.text.state.font = GetAppFont();
- defaults.text.state.size = GetDefFontSize();
- defaults.text.state.mode = srcOr;
- defaults.text.state.face = 0;
- defaults.text.wrap = true;
- defaults.text.buffer = false;
- defaults.text.margin = 6 * PIXELS_PER_INCH;
- defaults.text.just = GetSysJust();
- defaults.units.id = (IUMetric() ? RLS_UNITS_CENTIMETERS : RLS_UNITS_INCHES);
- check(1 <= defaults.units.id && defaults.units.id <= MAX_UNITS);
- defaults.units.conversion = gUnitConversions[defaults.units.id - 1];
- ResStrLen(RLS_UNITS_SINGULAR, defaults.units.id, defaults.units.singular, sizeof(CStr31));
- ResStrLen(RLS_UNITS_PLURAL, defaults.units.id, defaults.units.plural, sizeof(CStr31));
- initialized = true;
- }
- return(&defaults);
- }
-
- /* return application's global preferences structure */
- AppPrefsType *AppPrefs(void)
- {
- static AppPrefsType prefs;
- static Boolean initialized;
-
- if (! initialized) {
- prefs = *AppPrefsDefaults();
- initialized = true;
- }
- return(&prefs);
- }
-
- /* adjust size popup menu--set value, outline sizes, add/remove user's choice */
- static AdjustSizeMenu(AppPrefsWindowHandle prefs)
- {
- AppPrefsType *settings = (**prefs).appPrefs;
- ControlHandle ctl;
- MenuHandle menu;
- Str255 pstr;
- CStr255 str;
- short item;
-
- /* adjust user's choice */
- NumToString(settings->text.state.size, pstr);
- ctl = DlgCtl((**prefs).dlg, iSizePopup);
- menu = DlgPopupMenu((**prefs).dlg, iSizePopup);
- item = MenuFindItem(menu, p2cstrcpy(str, pstr));
- if (item == 0) {
-
- /* used entered a size not found in the menu, so add the
- user's choice as the first item in the menu (IM-VI, p2-37) */
- if (! (**prefs).sizeHasUserChoice) {
- short nitems;
- InsMenuItem(menu, (StringPtr) "\p(-", 0);
- InsMenuItem(menu, pstr, 0);
- for (nitems = CountMItems(menu); nitems > 0; nitems--)
- SetItemMark(menu, nitems, noMark);
- SetItemMark(menu, 1, checkMark);
- SetCtlMax(ctl, GetCtlMax(ctl) + 2);
- (**prefs).sizeHasUserChoice = true;
- }
- SetItem(menu, 1, pstr);
- SetCtlValue(ctl, 1);
- }
- else if (item > 2 && (**prefs).sizeHasUserChoice) {
-
- /* remove user's choice, since selected item is in menu */
- (**prefs).sizeHasUserChoice = false;
- SetCtlValue(ctl, 1);
- DelMenuItem(menu, 1);
- DelMenuItem(menu, 1);
- SetCtlMax(ctl, GetCtlMax(ctl) - 2);
- SetCtlValue(ctl, item - 2);
- }
- else
- SetCtlValue(ctl, item);
-
- /* adjust size menu */
- MenuOutlineSizes(DlgPopupMenu((**prefs).dlg, iSizePopup),
- FontID(settings->text.state.font), true);
- }
-
- static void SetupDialog(AppPrefsWindowHandle prefs)
- {
- AppPrefsType *settings = (**prefs).appPrefs;
- ControlHandle ctl;
- MenuHandle menu;
- Str255 pstr;
- CStr255 str;
- short item;
-
- /* set text kind radio buttons */
- switch (settings->text.kind) {
- case TX_STYLED_KIND:
- RadioClickID((**prefs).text.kindRadio, iStyledButton);
- break;
- case TX_UNSTYLED_KIND:
- RadioClickID((**prefs).text.kindRadio, iUnstyledButton);
- break;
- case TX_EXTENDED_KIND:
- RadioClickID((**prefs).text.kindRadio, iExtendedButton);
- break;
- }
-
- /* set text word wrap */
- TxWrapDialogValuesSet((**prefs).dlg, (**prefs).text.wrapRadio,
- iWrapButton, iWrapDontButton, iWrapMarginText, iWrapUnitsText,
- settings->text.wrap, settings->text.margin);
-
- /* set value of font popup menu */
- GetFontName(FontID(settings->text.state.font), pstr);
- menu = DlgPopupMenu((**prefs).dlg, iFontPopup);
- item = MenuFindItem(menu, p2cstrcpy(str, pstr));
- DlgCtlValueSet((**prefs).dlg, iFontPopup, item);
-
- /* adjust font size type-in menu and text */
- AdjustSizeMenu(prefs);
- DlgNumSet((**prefs).dlg, iSizeText, settings->text.state.size);
-
- /* set value of units popup menu */
- check(1 <= settings->units.id && settings->units.id <= MAX_UNITS);
- DlgCtlValueSet((**prefs).dlg, iUnitsPopup, settings->units.id);
-
- /* set value of justification popup menu */
- switch (settings->text.just) {
- case teJustRight: item = 3; break;
- case teJustCenter: item = 2; break;
- case teForceLeft: item = 1; break;
- case teJustLeft: item = 1; break;
- default: item = 1; break;
- }
- DlgCtlValueSet((**prefs).dlg, iJustPopup, item);
- }
-
- /* Handler which overrides the mouse down handler for the popup menu controls,
- allowing us to adjust the popup menus before they're selected. */
- static Boolean OverrideCtlMousedown(EventObjectType object, EventRecord *event)
- {
- ControlHandle ctl = object;
- DialogPtr dlg = CtlWindow(ctl);
- AppPrefsWindowHandle prefs = WinData(dlg);
-
- MenuEnable(CtlPopupMenu(ctl), 0, true);
- if (ctl == WinRegisteredID(dlg, iSizePopup)) {
- AdjustSizeMenu(prefs);
- DlgTextSelectAll(dlg, iSizeText);
- }
- return(CtlMouseDown(ctl, event));
- }
-
- /* create window to display and set preferences */
- AppPrefsWindowHandle AppPrefsBegin(AppPrefsType *appPrefs)
- {
- volatile AppPrefsWindowHandle prefs = NULL;
- DialogPtr dlg = NULL; /* the dialog displaying the prefs */
- RadioHandle radio = NULL; /* for setting up radio button groups */
- MenuHandle menu = NULL; /* for setting up popup menus */
- Rect frame, title; /* frame and title rectangles for radio buttons */
- static EventTableType overrideTable; /* for overriding event handler */
- short i;
-
- TRY {
- prefs = HandleBeginClear(sizeof(AppPrefsWindowType));
- (**prefs).appPrefs = appPrefs;
- dlg = DlgBegin(RLD_PREFERENCES);
- (**prefs).dlg = dlg;
-
- /* create text group frame; we use a radio button structure since
- it already handles display of a frame with a title, though no
- radio buttons are actually installed into it */
- DlgBox(dlg, iTextFrame, &frame);
- DlgBox(dlg, iTextTitle, &title);
- radio = RadioBegin(dlg, &frame, &title);
- (**prefs).text.frameRadio = radio;
-
- /* create text kind radio buttons */
- DlgBox(dlg, iStyleFrame, &frame);
- DlgBox(dlg, iStyleTitle, &title);
- radio = RadioBegin(dlg, &frame, &title);
- (**prefs).text.kindRadio = radio;
- RadioAdd(radio, DlgCtl(dlg, iStyledButton), iStyledButton);
- RadioAdd(radio, DlgCtl(dlg, iUnstyledButton), iUnstyledButton);
- RadioAdd(radio, DlgCtl(dlg, iExtendedButton), iExtendedButton);
- WinRegisterID(dlg, radio, iStyleRadioGroup);
-
- /* setup wrap margin items */
- radio = TxWrapDialogSetup(dlg, iWrapButton, iWrapDontButton,
- iWrapMarginText, iWrapUnitsText, iWrapFrame, iWrapTitle,
- (**prefs).appPrefs->text.wrap,
- (**prefs).appPrefs->text.margin);
- (**prefs).text.wrapRadio = radio;
- WinRegisterID(dlg, radio, iWrapRadioGroup);
-
- /* setup units popup menu */
- menu = DlgPopupMenu(dlg, iUnitsPopup);
- check(MenuValid(menu));
- if (CountMItems(menu) == 0) {
- for (i = 1; i < RLS_UNITS_LAST; i++) {
- CStr31 name;
- ResStrLen(RLS_UNITS_PLURAL, i, name, sizeof(CStr31));
- AppendMenu(menu, c2pstr(name));
- }
- DlgCtlMaxSet(dlg, iUnitsPopup, CountMItems(menu));
- }
-
- /* override mouse down handlers for popup menus */
- overrideTable = *(const EventTableType *) CtlEventTable();
- overrideTable.focusWindow.mousedown = OverrideCtlMousedown;
- WinObjectTableSet(dlg, DlgCtl(dlg, iSizePopup), &overrideTable);
- WinObjectTableSet(dlg, DlgCtl(dlg, iFontPopup), &overrideTable);
- WinObjectTableSet(dlg, DlgCtl(dlg, iJustPopup), &overrideTable);
- WinObjectTableSet(dlg, DlgCtl(dlg, iUnitsPopup), &overrideTable);
- check(WinData(dlg) == NULL);
- WinDataSet(dlg, prefs);
-
- /* set font size text field to be an integer field */
- TxHookKeySet(WinRegisteredID(dlg, iSizeText), TxHookKeyUnsignedInteger);
-
- /* finish setting up window */
- SetupDialog(prefs);
- DlgTextSelectAll((**prefs).dlg, iWrapMarginText);
- WinRegister(dlg, prefs, AppPrefsEventTable());
- WinZoomRestore(dlg, PrefsFile(), PREFS_APPLICATION_POSITION);
- WinShow(dlg);
- } CATCH {
- AppPrefsEnd(prefs);
- } ENDTRY;
- return(prefs);
- }
-
- /* dispose of the preferences window */
- void AppPrefsEnd(AppPrefsWindowHandle prefs)
- {
- if (prefs) {
- if ((**prefs).dlg)
- WinZoomSave((**prefs).dlg, PrefsFile(), PREFS_APPLICATION_POSITION);
- WinUnregister((**prefs).dlg, prefs);
- RadioEnd((**prefs).text.frameRadio);
- RadioEnd((**prefs).text.kindRadio);
- RadioEnd((**prefs).text.wrapRadio);
- DlgEnd((**prefs).dlg);
- HandleEnd(prefs);
- }
- }
-
- /* handle a click in the preferences window */
- void AppPrefsClicked(AppPrefsWindowHandle prefs, long clickedID)
- {
- Boolean wrap; /* for getting word wrap */
- float margin; /* for getting wrap margin */
- short font; /* for getting font */
- long size; /* for getting font size */
- Str255 item; /* for getting menu items */
-
- switch (clickedID) {
- case iStyleRadioGroup:
- switch (RadioSelectedID((**prefs).text.kindRadio)) {
- case iStyledButton: (**prefs).appPrefs->text.kind = TX_STYLED_KIND; break;
- case iUnstyledButton:(**prefs).appPrefs->text.kind = TX_UNSTYLED_KIND; break;
- case iExtendedButton:(**prefs).appPrefs->text.kind = TX_EXTENDED_KIND; break;
- }
- SetupDialog(prefs);
- break;
- case iWrapMarginText:
- RadioClickID((**prefs).text.wrapRadio, iWrapButton);
- /* no break */
- case iWrapRadioGroup:
- TxWrapDialogValues((**prefs).dlg, (**prefs).text.wrapRadio,
- iWrapButton, iWrapDontButton, iWrapMarginText, &wrap, &margin);
- (**prefs).appPrefs->text.wrap = wrap;
- (**prefs).appPrefs->text.margin = margin;
- if (clickedID != iWrapMarginText)
- SetupDialog(prefs); /* don't call for text field */
- break;
- case iFontPopup:
- GetItem(DlgPopupMenu((**prefs).dlg, iFontPopup),
- DlgCtlValue((**prefs).dlg, iFontPopup), item);
- GetFNum(item, &font);
- (**prefs).appPrefs->text.state.font = font;
- SetupDialog(prefs);
- break;
- case iSizeText:
- size = DlgNum((**prefs).dlg, iSizeText);
- if (size < TX_MIN_FONT)
- size = TX_MIN_FONT;
- else if (size > TX_MAX_FONT)
- size = TX_MAX_FONT;
- (**prefs).appPrefs->text.state.size = size;
- /* don't call SetupDialog for open text field, or it will overwrite
- whatever the user is typing */
- break;
- case iSizePopup:
- GetItem(DlgPopupMenu((**prefs).dlg, iSizePopup),
- DlgCtlValue((**prefs).dlg, iSizePopup), item);
- StringToNum(item, &size);
- if (size < TX_MIN_FONT)
- size = TX_MIN_FONT;
- else if (size > TX_MAX_FONT)
- size = TX_MAX_FONT;
- (**prefs).appPrefs->text.state.size = size;
- SetupDialog(prefs);
- break;
- case iJustPopup:
- switch (DlgCtlValue((**prefs).dlg, iJustPopup)) {
- case 1: (**prefs).appPrefs->text.just = teForceLeft; break;
- case 2: (**prefs).appPrefs->text.just = teJustCenter; break;
- case 3: (**prefs).appPrefs->text.just = teJustRight; break;
- }
- SetupDialog(prefs);
- break;
- case iUnitsPopup:
- (**prefs).appPrefs->units.id = DlgCtlValue((**prefs).dlg, iUnitsPopup);
- (**prefs).appPrefs->units.conversion = gUnitConversions[(**prefs).appPrefs->units.id - 1];
- check(1 <= (**prefs).appPrefs->units.id && (**prefs).appPrefs->units.id <= MAX_UNITS);
- ResStrLen(RLS_UNITS_SINGULAR, (**prefs).appPrefs->units.id, (**prefs).appPrefs->units.singular, sizeof(CStr31));
- ResStrLen(RLS_UNITS_PLURAL, (**prefs).appPrefs->units.id, (**prefs).appPrefs->units.plural, sizeof(CStr31));
- SetupDialog(prefs);
- break;
- case iDefaultsButton:
- *(**prefs).appPrefs = *AppPrefsDefaults();
- SetupDialog(prefs);
- DlgTextSelectAll((**prefs).dlg, iWrapMarginText);
- break;
- default:
- SetupDialog(prefs);
- break;
- }
- }
-
- /* create and/or select the preferences window */
- void AppPrefsShow(void)
- {
- if (! gAppPrefsWindow)
- gAppPrefsWindow = AppPrefsBegin(AppPrefs());
- WinSelect((**gAppPrefsWindow).dlg);
- }
-
- /* hide the preferences window */
- void AppPrefsHide(void)
- {
- if (gAppPrefsWindow) {
- AppPrefsWrite((**gAppPrefsWindow).appPrefs);
- AppPrefsEnd(gAppPrefsWindow);
- gAppPrefsWindow = NULL;
- }
- }
-
- /* read the preferences data from the preferences file */
- void AppPrefsRead(AppPrefsType *prefs)
- {
- size_t size;
- long version;
- volatile Boolean failed = false;
-
- TRY {
- *prefs = *AppPrefsDefaults();
- if (! failed) {
- FailInfoSet(RLS_ERR_READ, FileName(PrefsFile()), NULL);
- PrefsOpen();
- if (ResExists1(RES_PREF_TYPE, PREFS_APPLICATION)) {
- version = APP_PREFS_VERSION;
- size = sizeof(AppPrefsType);
- ArchiveReadRes(RES_PREF_TYPE, PREFS_APPLICATION, prefs, &size, &version);
- if (size != sizeof(AppPrefsType) || version != APP_PREFS_VERSION)
- *prefs = *AppPrefsDefaults();
- }
- PrefsClose();
- FailInfoClear();
- }
- } CATCH {
- if (! failed) {
- failed = true;
- PrefsClose();
- FailDisplay();
- FailClear();
- RETRY;
- }
- } ENDTRY;
- }
-
- /* write the preferences data to the preferences file */
- void AppPrefsWrite(const AppPrefsType *prefs)
- {
- volatile Boolean opened = false;
- volatile Boolean failed = false;
-
- TRY {
- if (! failed) {
- FailInfoSet(RLS_ERR_WRITE, FileName(PrefsFile()), NULL);
- if (! PrefsReferenceNumber()) {
- PrefsOpen();
- opened = true;
- }
- ArchiveWriteRes(RES_PREF_TYPE, PREFS_APPLICATION, prefs,
- sizeof(AppPrefsType), APP_PREFS_VERSION);
- if (opened)
- PrefsClose();
- FailInfoClear();
- }
- } CATCH {
- if (! failed) {
- failed = true;
- if (opened)
- PrefsClose();
- FailDisplay();
- FailClear();
- RETRY;
- }
- } ENDTRY;
- }
-
- /* handle a preferences related menu command */
- Boolean AppPrefsMenu(const MenuPickType *pick)
- {
- Boolean handled = false;
-
- switch (pick->cmd) {
- case CMD_PREFERENCES:
- AppPrefsShow();
- handled = true;
- break;
- case CMD_CLOSE:
- if (gAppPrefsWindow && FocusWindow() == (**gAppPrefsWindow).dlg) {
- AppPrefsHide();
- handled = true;
- }
- break;
- }
- return(handled);
- }
-
- /* adjust preferences related menu items */
- void AppPrefsAdjustMenu(void)
- {
- if (gAppPrefsWindow && FocusWindow() == (**gAppPrefsWindow).dlg) {
- MenuCmdEnable(CMD_CLOSE);
- MenuCmdCheck(CMD_PREFERENCES, true);
- }
- if (! WinModalHasFocus() && MemWarning() < MEM_WARNING_VERY_LOW) {
- MenuCmdEnable(CMD_PREFERENCES);
- MenuCmdEnable(CMD_EDIT);
- }
- }
-
- /* close preferences window if memory is low */
- void AppPrefsMemoryLow(void)
- {
- if (MemWarning() >= MEM_WARNING_VERY_LOW)
- AppPrefsHide();
- }
-